#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<string.h>
#include"MagicTower.h"
//初始化玩家
void InitPlayer(P* player)
{
    player->HP = 100;
    player->attack = 10;
    player->now_money = 100;
    player->defense = 1;
    player->count_add_blood = 1;
    player->count_add_defense = 1;
    player->count_monsters_Dizzy = 1;
    player->count_treasures = 0;
    player->Dizzy = 0;
    player->x = 0;
    player->y = 0;
}
//设置随机数
int GetRandNumber(int max)
{
    return rand() % max;
}
//创建怪兽，返回怪兽的指针
M* CreateMonster(const char* name, int HP, int attack, int kill_money)
{
    M* monster = (M*)malloc(sizeof(M));
    if (monster == NULL)
    {
        printf("CreateMonster malloc error!\n");
        return NULL;
    }
    Initialize(&monster->name, name);
    monster->kill_money = kill_money;
    monster->HP = HP;
    monster->attack = attack;

    monster->x = GetRandNumber(Map_Size);
    monster->y = GetRandNumber(Map_Size);
    return monster;
}
//创建宝物，返回宝物的指针
T* CreateTreasure(const char* name, int value)
{
    T* treasure = (T*)malloc(sizeof(T));
    if (treasure == NULL)
    {
        printf("CreateTreasure malloc error!\n");
        return NULL;
    }
    Initialize(&treasure->name, name);
    treasure->value = value;
    treasure->flag = 1;

    treasure->x = GetRandNumber(Map_Size);
    treasure->y = GetRandNumber(Map_Size);
    return treasure;
}

//初始化怪兽，并存入到动态数组中，动态数组中存放的是怪兽的指针
void InitMonsters(DmArr* array)
{
    if (InitArray(array) == false)
    {
        return;
    }

    InsertArray(array, CreateMonster("巨龙", 100, 20, 50));
    InsertArray(array, CreateMonster("食人魔", 50, 10, 30));
    InsertArray(array, CreateMonster("食人魔", 50, 10, 30));
    InsertArray(array, CreateMonster("食人魔", 50, 10, 30));
    InsertArray(array, CreateMonster("哥布林", 20, 5, 10));
    InsertArray(array, CreateMonster("哥布林", 20, 5, 10));
    InsertArray(array, CreateMonster("哥布林", 20, 5, 10));
    InsertArray(array, CreateMonster("哥布林", 20, 5, 10));
    InsertArray(array, CreateMonster("哥布林", 20, 5, 10));
}
//初始化宝物，并存入到动态数组中，动态数组中存放的是宝物的指针
void InitTreasure(DmArr* array)
{
    if (InitArray(array) == false)
    {
        return;
    }
    InsertArray(array, CreateTreasure("宝藏", 100));
    InsertArray(array, CreateTreasure("血瓶", 50));
    InsertArray(array, CreateTreasure("血瓶", 50));
    InsertArray(array, CreateTreasure("血瓶", 50));
    InsertArray(array, CreateTreasure("霸体", 10));
    InsertArray(array, CreateTreasure("霸体", 10));
    InsertArray(array, CreateTreasure("霸体", 10));
    InsertArray(array, CreateTreasure("眩晕", 20));
    InsertArray(array, CreateTreasure("眩晕", 20));
}
//键盘操作人物移动，商店操作，背包操作
void MakeMove(P* player, char symbol)
{
    switch (symbol)
    {
    case 'W':
    case 'w':
        player->x--;
        break;
    case 'S':
    case 's':
        player->x++;
        break;
    case 'A':
    case 'a':
        player->y--;
        break;
    case 'D':
    case 'd':
        player->y++;
        break;
        //按下M打开商店
    case 'M':
    case 'm':
        printf("欢迎来到精灵商店!需要点啥!\n");
        printf("1.宝藏:%d金币\n", 100);
        printf("2.霸体:%d金币\n", 10);
        printf("3.血瓶:%d金币\n", 50);
        printf("4.眩晕:%d金币\n", 20);
        int choice3 = 0;
        scanf("%d", &choice3);
        switch (choice3)
        {
        case 1:
            if (player->now_money >= 100)
            {
                player->count_treasures++;
                printf("宝藏购买成功!,欢迎再来喔！\n");
                player->now_money -= 100;
                printf("您的余额为%d\n", player->now_money);
            }
            else
            {
                printf("钱不够啦，快去打怪兽攒钱！\n");
            }
            break;
        case 2:
            if (player->now_money >= 10)
            {
                player->count_add_defense++;
                printf("霸体购买成功!,欢迎再来喔！\n");
                player->now_money -= 10;
                printf("您的余额为%d\n", player->now_money);
            }
            else
            {
                printf("钱不够啦，快去打怪兽攒钱！\n");
            }
            break;
        case 3:
            if (player->now_money >= 50)
            {
                player->count_add_blood++;
                printf("血瓶购买成功!,欢迎再来喔！\n");
                player->now_money -= 50;
                printf("您的余额为%d\n", player->now_money);
            }
            else
            {
                printf("钱不够啦，快去打怪兽攒钱！\n");
            }
            break;
        case 4:
            if (player->now_money >= 20)
            {
                player->count_monsters_Dizzy++;
                printf("眩晕购买成功!,欢迎再来喔！\n");
                player->now_money -= 20;
                printf("您的余额为%d\n", player->now_money);
            }
            else
            {
                printf("钱不够啦，快去打怪兽攒钱！\n");
            }
            break;
        default:
            break;
        }
        break;
        //按下b打开背包
    case 'B':
    case 'b':
        printf("===================================\n");
        printf("*************背包******************\n");
        printf("===================================\n");
        printf("金币的数量：%d\n", player->now_money);
        printf("宝藏的数量:%d\n", player->count_treasures);
        printf("血瓶的数量:%d\n", player->count_add_blood);
        printf("霸体的数量:%d\n", player->count_add_defense);
        printf("眩晕的数量:%d\n", player->count_monsters_Dizzy);
        break;
    default:break;
    }
    if (player->x < 0) player->x = 0;
    if (player->x >= Map_Size) player->x = Map_Size - 1;
    if (player->y < 0) player->y = 0;
    if (player->y >= Map_Size) player->y = Map_Size - 1;
}

//战斗实现
int Battle(P* player, M* monster,DmArr *MonsterArr)
{
    system("clear");
    printf("您遭受了|%s| 血量:|%d| 攻击力:|%d|\n", monster->name.string, monster->HP, monster->attack);
    printf("---------------------------------------------\n");
    printf("*                   开始战斗!                 *\n");
    printf("---------------------------------------------\n");
    while (player->HP > 0 && monster->HP > 0)
    {
        printf("请选择您要执行的行为\n");
        printf("1、普通攻击\n");
        printf("2、暴击\n");
        printf("3、逃跑\n");
        printf("4、使用增益\n");
        int choice;
        scanf("%d", &choice);
        printf("======================战斗报告========================\n");
        switch (choice)
        {
        case 1:
            if (player->Dizzy == 1)
            {
                printf("怪物已经被眩晕了，快攻击他\n");
                player->Dizzy = 0;
            }
            else
            {
                player->HP -= (monster->attack - player->defense);
                printf("|%s|:对你造成了%d的伤害,您的剩余血量为:%d\n", monster->name.string, monster->attack - player->defense, player->HP);
                if (player->HP <= 20)
                {
                    printf("血量快见底了，不用补点血吗？\n");
                }
            }
            monster->HP -= player->attack;
            printf("你对|%s|造成了%d的伤害,怪物的血量为%d\n", monster->name.string, player->attack, monster->HP);
            break;
        case 2:
            if (GetRandNumber(2) == 1)
            {
                if (player->Dizzy == 1)
                {
                    printf("怪物已经被眩晕了，快攻击他\n");
                    player->Dizzy = 0;
                }
                else
                {
                    player->HP -= (monster->attack - player->defense);
                    printf("|%s|:对你造成了%d的伤害,您的剩余血量为:%d\n", monster->name.string, monster->attack - player->defense, player->HP);
                    if (player->HP <= 20)
                    {
                        printf("血量快见底了，不用补点血吗？\n");
                    }
                }
                monster->HP -= player->attack * 2;
                printf("你对|%s|造成了%d的伤害,怪物的血量为%d\n", monster->name.string, player->attack * 2, monster->HP);
            }
            else
            {
                player->HP -= monster->attack;
                printf("暴击失败，无法发动攻击\n");
                printf("|%s|:对你造成了%d的伤害,您的剩余血量为:%d,怪物的血量为%d\n", monster->name.string, monster->attack - player->defense, player->HP, monster->HP);
                if (player->HP <= 20)
                {
                    printf("血量快见底了，不用补点血吗？\n");
                }
            }
            break;
        case 3:
            if (GetRandNumber(2) == 1)
            {
                printf("逃跑成功\n");
                printf("您的剩余血量为:%d\n", player->HP);
                player->x += 1;
                player->y += 1;
                return true;
            }
            else
            {
                player->HP -= (monster->attack - player->defense);
                printf("逃跑失败，无法发动攻击\n");
                printf("|%s|:对你造成了%d的伤害,您的剩余血量为:%d,怪物的血量为%d\n", monster->name.string, monster->attack - player->defense, player->HP, monster->HP);
                if (player->HP <= 20)
                {
                    printf("血量快见底了，不用补点血吗？\n");
                }
            }
            break;
            //使用宝物
        case 4:
            printf("请选择您需要使用的增益:\n");
            printf("1.宝藏\n");
            printf("2.血瓶\n");
            printf("3.霸体\n");
            printf("4.眩晕\n");
            int choice2 = 0;
            scanf("%d", &choice2);
            switch (choice2)
            {
            case 1:
                if (player->count_treasures > 0)
                {
                    player->attack *= 2;
                    player->defense += 5;
                    player->HP += 20;
                    player->count_treasures--;
                    printf("您当前的战斗力为:攻击：%d,血量：%d,防御：%d,宝藏的剩余数量为%d\n", player->attack, player->HP, player->defense, player->count_treasures);
                }
                else
                {
                    printf("您的宝藏数量不足1,请继续探索吧\n");
                }
                break;
            case 2:
                if (player->count_add_blood > 0)
                {
                    player->HP += 10;
                    player->count_add_blood--;
                    printf("您当前的战斗力为:攻击：%d,血量：%d,防御：%d,血瓶的剩余数量为%d\n", player->attack, player->HP, player->defense, player->count_add_blood);
                }
                else
                {
                    printf("您的血瓶数量不足1,请继续探索吧\n");
                }
                break;
            case 3:
                if (player->count_add_defense > 0)
                {
                    player->defense += 5;
                    player->count_add_defense--;
                    printf("您当前的战斗力为:攻击：%d,血量：%d,防御：%d,霸体的剩余数量为%d\n", player->attack, player->HP, player->defense, player->count_add_defense);
                }
                else
                {
                    printf("您的霸体数量不足1,请继续探索吧\n");
                }
                break;
            case 4:
                if (player->count_monsters_Dizzy > 0)
                {
                    player->Dizzy = 1;
                    printf("使用成功！下次攻击怪物将被眩晕一次，加油召唤师！\n");
                    player->count_monsters_Dizzy--;
                    printf("您当前的战斗力为:攻击：%d,血量：%d,防御：%d,眩晕的剩余数量为%d\n", player->attack, player->HP, player->defense, player->count_monsters_Dizzy);
                }
                else
                {
                    player->Dizzy = 0;
                    printf("您的眩晕数量不足1,请继续探索吧\n");
                }
                break;
            default:
                break;
            }
            break;
        default:
            break;
        }
        printf("\n=======================end========================\n");
        if (player->HP <= 0)
        {
            printf("你被|%s|击败了!\n", monster->name.string);
            player->HP = 0;
            return false;
        }
        if (monster->HP <= 0)
        {
            for(int i = 0;i < MonsterArr->len;i++)
            {
                M* currentmonster = (M *)MonsterArr->dp[i];
                if(currentmonster->HP <= 0)
                {
                    DeleteArray(MonsterArr,i+1);
                }
            }
            printf("剩余怪物数量:%d\n",MonsterArr->len);
            printf("你击败了|%s|!\n", monster->name.string);
            player->now_money += monster->kill_money;
            printf("恭喜您获得了%d的金币,快去购物吧!\n", monster->kill_money);
            printf("你当前的血量为:%d\n", player->HP);
            monster->HP = 0;
            return true;
        }
    }
}
//初始化地图
int InitBoard(char(*p)[Map_Size],DmArr *monsters)
{
    for (int i = 0; i < Map_Size; i++)
    {
        for (int j = 0; j < Map_Size; j++)
        {
            p[i][j] = '-';
        }
    }
}
//打印地图
void PrintMap(char(*p)[Map_Size], P* player,DmArr *monsters)
{
    InitBoard(p,monsters);
    p[player->x][player->y] = 'X';
    printf("     ");
    for (int i = 0; i < Map_Size; i++)
    {
        printf("%4d ", i + 1);
    }
    printf("\n");
    for (int i = 0; i < Map_Size; i++)
    {
        printf("%4d ", i + 1);
        for (int j = 0; j < Map_Size; j++)
        {
            printf("%4c ", p[i][j]);
        }
        printf("\n");
    }

}

//玩法实现
void Game(DmArr *treasures,DmArr *monsters,struct Player *player,char board[Map_Size][Map_Size],char *userID,char(*p)[Map_Size])
{
    while(1)
    {
        printf("本局怪物数量个数还剩：%d个\n",monsters->len);
        if(monsters->len == 0)
        {
            printf("恭喜通过，你将获得500大洋的奖励！，快去打开背包查看吧！,后续关卡正在开发中！\n");
            player->now_money += 500;
            break;
        }
        PrintMap(board, player,monsters);
        printf("您当前的位置是<%d %d>\n", player->x + 1, player->y + 1);
        //遍历宝物数组，判断玩家位置是否和宝物位置相同
        for (int i = 0; i < treasures->len; i++)
        {
            T* treasure = (T*)treasures->dp[i];
            if (player->x == treasure->x && player->y == treasure->y)
            {
                if (strcmp(treasure->name.string, "宝藏") == 0)
                {
                    printf("哇塞！你发现了一个超级大宝藏，他能全面提升你的能力，快拿上他和怪物战斗吧！加油冒险家！\n");
                    player->count_treasures++;
                    treasure->flag = 0;
                }
                if (strcmp(treasure->name.string, "血瓶") == 0)
                {
                    printf("这里有个血瓶！使用它可以为你恢复血量！\n");
                    player->count_add_blood++;
                    treasure->flag = 0;
                }
                if (strcmp(treasure->name.string, "霸体") == 0)
                {
                    printf("捡到了一个霸体药剂，喝下去能让冒险家的防御大大提升！被怪兽打再也不怕疼了！！\n");
                    player->count_add_defense++;
                    treasure->flag = 0;
                }
                if (strcmp(treasure->name.string, "眩晕") == 0)
                {
                    printf("眩晕药剂铁铁！能把怪兽一下子打晕！记得只能眩晕一次！\n");
                    player->count_monsters_Dizzy++;
                    treasure->flag = 0;
                }
                //设置宝物的标志位，当宝物被捡到，将标志位赋值为0，遍历宝物数组，如果标志位为0，删除此宝物
                for(int i = 0;i < treasures->len;i++)
                {
                    T* currenttreasure = (T *)treasures->dp[i];
                    if(currenttreasure->flag == 0)
                    {
                        DeleteArray(treasures,i+1);
                    }
                }
            }
        }
        //遍历怪物数组，判断玩家位置是否和怪物位置相同，相同则调用Battle函数
        for (int i = 0; i < monsters->len; i++)
        {
            M* monster = (M*)monsters->dp[i];

            if (monster->HP > 0 && monster->x == player->x && monster->y == player->y)
            {
                if (Battle(player, monster,monsters) == false)
                {
                    printf("Game Over!\n");
                    break;
                }
            }
        }
        if (player->HP == 0)
            break;
        printf("请选择你要进行的移动(输入:'w','a','s','d',输入'm'打开商店,输入'b'查看背包,输入'q'退出游戏):\n");
        char choice;
        scanf("%s", &choice);
        system("clear");
        //退出操作，退出前询问是否进行保存
        if (strcmp(&choice, "q") == 0)
        {
            printf("是否要进行保存? y/n\n");
            scanf("%s",&choice);
            if(strcmp(&choice,"y") == 0)
            {
                //存档，会自动将存档文件的名字变成玩家的名字，方便下次读档时匹配到该玩家的档案
                char *file = (char *)malloc(sizeof(char)*10);
                strcpy(file,userID);
                strcat(file,".txt");
                SaveGameProcess(treasures,monsters,player,file);
                printf("您已保存退出游戏\n");
                free(file);
                break;
            }
            //直接退出游戏
            else
            {
                printf("您已退出游戏\n");
                break;
            } 
        }
        //不退出，继续游戏
        else
        {
            MakeMove(player, choice);
        }
    }
}
//将游戏进度按照格式化输入的形式存入到文档中
void PutInTxt(DmArr *treasures,DmArr *monsters,struct Player *player,FILE *file)
{
    fprintf(file,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",\
    player->attack,player->count_add_blood,player->count_add_defense,player->count_monsters_Dizzy,player->count_treasures,\
    player->defense,player->Dizzy,player->HP,player->now_money,player->x,player->y);
    for(int i = 0;i < monsters->len;i++)
    {
        M* monster = (M*)monsters->dp[i];
        if(i == monsters->len - 1)
            fprintf(file,"%s,%d,%d,%d,%d,%d\n",monster->name.string,monster->HP,monster->attack,monster->kill_money, monster->x,monster->y);
         else
             fprintf(file,"%s,%d,%d,%d,%d,%d:",monster->name.string,monster->HP,monster->attack,monster->kill_money, monster->x,monster->y);
    }
    for(int i = 0;i < treasures->len;i++)
    {
        T* treasure = (T*)treasures->dp[i];
        if(i == treasures->len - 1)
            fprintf(file,"%s,%d,%d\n",treasure->name.string,treasure->x,treasure->y);
        else
            fprintf(file,"%s,%d,%d:",treasure->name.string,treasure->x,treasure->y);
    }
    fflush(file);
}
//保存游戏的进度
void SaveGameProcess(DmArr *treasures,DmArr *monsters,struct Player *player,const char *FilePath)
{
    FILE *file = fopen(FilePath,"w");
    if(file == NULL)
    {
        printf("SaveGameProcess open file error!\n");
        return;
    }
    PutInTxt(treasures,monsters,player,file);
    fclose(file);
}


//读档时将上次的怪物信息存入到动态数组中
M* RenewMonster(char* name, int HP, int attack, int kill_money,int x,int y)
{
    M* monster = (M*)malloc(sizeof(M));
    if (monster == NULL)
    {
        printf("CreateMonster malloc error!\n");
        return NULL;
    }
    Initialize(&monster->name, name);
    monster->kill_money = kill_money;
    monster->HP = HP;
    monster->attack = attack;

    monster->x = x;
    monster->y = y;
    return monster;
}
//读档时将上次的宝物信息存入到动态数组中

T* RenewTreasure(char* name, int x,int y)
{
    T* treasure = (T*)malloc(sizeof(T));
    if (treasure == NULL)
    {
        printf("RenewTreasure malloc error!\n");
        return NULL;
    }
    Initialize(&treasure->name, name);
    

    treasure->x = x;
    treasure->y = y;
    return treasure;
}

//读档，按行读取玩家的位置，血量等信息，读取下一行怪物信息，读取第三行的宝物信息
void LoadGameProcess(DmArr *monster, DmArr *treasure,struct Player *player,const char *FilePath,DBL *monsterlist)
{
    //读取玩家信息
    FILE *file = fopen(FilePath,"r");
    if(file == NULL)
    {
        printf("SaveGameProcess open file error!\n");
        return;
    }
    char line[200];   
    fscanf(file,"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",\
    &player->attack,&player->count_add_blood,&player->count_add_defense,&player->count_monsters_Dizzy,&player->count_treasures,\
    &player->defense,&player->Dizzy,&player->HP,&player->now_money,&player->x,&player->y);
    
    //读取怪物信息
    DBL list;
    InitDBLinkList(&list);
    if (fgets(line, sizeof(line), file)) 
    {
        line[strcspn(line, "\n")] = '\0';
        char *token = strtok((char *)line, ":");
        while (token != NULL) 
        {
            DBInsertTail(&list, token); 
            token = strtok(NULL, ":");
        }
    }
    struct Node *current = list.head;
    while (current != NULL)
    {
        char *temp = strtok((char *)current->data, ",");
        int hp = atoi(strtok(NULL, ","));
        int attack = atoi(strtok(NULL, ","));
        int killmoney = atoi(strtok(NULL, ","));
        int monster_x = atoi(strtok(NULL, ","));
        int monster_y = atoi(strtok(NULL, ","));
        current = current->next;
        InsertArray(monster,RenewMonster(temp,hp,attack,killmoney,monster_x,monster_y));
    }
    
    //读取宝物信息
    memset(line,0,200);
    DBL list2;
    fseek(file, 1, SEEK_CUR);
    InitDBLinkList(&list2);
    if (fgets(line, sizeof(line), file)) 
    {
        line[strcspn(line, "\n")] = '\0';
        char *token = strtok((char *)line, ":");
        while (token != NULL) 
        {
            DBInsertTail(&list2, token); 
            token = strtok(NULL, ":");
        }
    }
    struct Node *current2 = list2.head;
    while (current2 != NULL)
    {
        char *temp = strtok((char *)current2->data, ",");    
        int treasure_x = atoi(strtok(NULL, ","));
        int treasure_y = atoi(strtok(NULL, ","));
        current2 = current2->next;
        InsertArray(treasure,RenewTreasure(temp,treasure_x,treasure_y)); 
    }
    rewind(file);
}
